package com.open.exam.utils;

import com.google.gson.GsonBuilder;
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;
import com.mashape.unirest.http.exceptions.UnirestException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.util.StringUtils;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.util.*;

import static org.apache.http.HttpHeaders.USER_AGENT;

/**
 * Created by lucky on 2017/8/7.
 */
public class HttpRequestUtils {

    private static Logger logger = LoggerFactory.getLogger(HttpRequestUtils.class);
    /**
     * Do post string.
     *
     * @param baseUrl  the base url
     * @param apiUrl   the api url
     * @param paramMap the param map
     * @param headers  the headers
     * @return the string
     */
    public static String doPost(String baseUrl, String apiUrl, Map<String, Object> paramMap, Map<String, String> headers) {
        return send(baseUrl, apiUrl, paramMap, headers, "POST");
    }

    public static String doGet(String baseUrl, String apiUrl, Map<String, Object> paramMap, Map<String, String> headers) {
        return send(baseUrl, apiUrl, paramMap, headers, "GET");
    }
    /**
     * Do post string.
     *
     * @param baseUrl  the base url
     * @param apiUrl   the api url
     * @param paramMap the param map
     * @param headers  the headers
     * @return the string
     */
    public static String doDelete(String baseUrl, String apiUrl, Map<String, Object> paramMap, Map<String, String> headers) {
        return send(baseUrl, apiUrl, paramMap, headers, "DELETE");
    }

    /**
     * 处理请求
     *
     * @param baseUrl       the base url
     * @param apiUrl        the api url
     * @param paramMap      the param map
     * @param headers       the headers
     * @param requestMethod the request method
     * @return string
     */
    public static String send(String baseUrl, String apiUrl, Map<String, Object> paramMap, Map<String, String> headers, String requestMethod) {
        return send(baseUrl, apiUrl, paramMap, headers, requestMethod, null);
    }

    /**
     * 处理请求,
     *
     * @param baseUrl       the base url
     * @param apiUrl        the api url
     * @param paramMap      the param map
     * @param headers       the headers
     * @param requestMethod the request method
     * @param files         the files
     * @return string
     */
    public static String send(String baseUrl, String apiUrl, Map<String, Object> paramMap, Map<String, String> headers, String requestMethod, Map<String, String> files) {
        String resultStr = "";
        String filePath = null;
        try {

            System.setProperty("sun.net.http.allowRestrictedHeaders", "true");
            String url = baseUrl + apiUrl;
            if (requestMethod.equals("GET")) {
                //GET请求直接在链接后面拼上请求参数
                if(paramMap != null){
                    url += loadParamStr(paramMap);
                }
            }
            URL postURL = new URL(url);
            HttpURLConnection conn = (HttpURLConnection) postURL.openConnection();
            conn.setDoInput(true);//允许输入
            //设置连接超时时间和读取超时时间，单位：毫秒
            conn.setConnectTimeout(3000);
            conn.setReadTimeout(180000);
            conn.setRequestMethod(requestMethod);
            conn.setUseCaches(false);  // 不允许使用缓存
            conn.setInstanceFollowRedirects(true);
            conn.setRequestProperty("Accept-Charset", "utf-8");
            conn.setRequestProperty("Accept", "application/json");//要求服务端返回的数据类型
            if(headers == null){
                conn.setRequestProperty("Authorization","Basic YTE5NjNhYzA4MTY1NWE2YToyMzFhNzFjMWZlYmI0MTFkOGFmZjAwNDgxOWZjMTgzZA==");
            } else if(!headers.containsKey("Authorization")){
                conn.setRequestProperty("Authorization","Basic YTE5NjNhYzA4MTY1NWE2YToyMzFhNzFjMWZlYmI0MTFkOGFmZjAwNDgxOWZjMTgzZA==");
            }

            if (requestMethod.equals("PUT") || requestMethod.equals("POST")) {
                // 发送POST请求必须设置为true  允许输出
                conn.setDoOutput(true);
            } else {
                //Get请求不需要DoOutPut
                conn.setDoOutput(false);
            }
//            conn.setRequestProperty("Content-Type", "application/json;charset=utf-8");//json格式上传的模式
            conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");//表单上传的模式

            if (headers != null) {
                for (String pKey : headers.keySet()) {
                    if (!StringUtils.isEmpty(headers.get(pKey))) {
                        conn.setRequestProperty(pKey, headers.get(pKey));

                    }
                }
            }
            // POST的请求参数写在正文中
            int contentLength = 0;
            if (requestMethod.equals("PUT") || requestMethod.equals("POST")) {
                if (paramMap != null && !paramMap.isEmpty()) {
                    StringBuffer buffer = new StringBuffer();
                    for (Map.Entry<String, Object> entry : paramMap.entrySet()) {
                        buffer.append(entry.getKey()).append("=");
                        if (entry.getValue() != null) {
                            buffer.append(URLEncoder.encode(entry.getValue().toString(), "utf-8"));
                        } else {
                            buffer.append(" ");
                        }
                        buffer.append("&");
                    }
                    buffer.deleteCharAt(buffer.length() - 1);

                    String BOUNDARY = "";

                    if (files != null) {
                        BOUNDARY = UUID.randomUUID().toString();
                        conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + BOUNDARY);
                    }

                    DataOutputStream outStream = new DataOutputStream(conn.getOutputStream());
//                    outStream.write(buffer.toString().getBytes());
                    outStream.write(JSONObject.valueToString(paramMap).getBytes());
                    contentLength = buffer.length();

                    // file
                    if (files != null) {
                        Iterator<Map.Entry<String, String>> iter = files.entrySet().iterator();
                        while (iter.hasNext()) {
                            Map.Entry<String, String> entry = iter.next();
                            String inputName = (String) entry.getKey();
                            String inputValue = (String) entry.getValue();
                            if (inputValue == null) {
                                continue;
                            }
                            filePath = inputValue;
                            File file = new File(inputValue);
                            String filename = file.getName();

                            StringBuffer strBuf = new StringBuffer();
                            strBuf.append("\r\n").append("--").append(BOUNDARY).append("\r\n");
                            strBuf.append("Content-Disposition: form-data; name=\"" + inputName + "\"; filename=\"" + filename + "\"\r\n");
                            strBuf.append("Content-Type:application/octet-stream;\r\n\r\n");

                            outStream.write(strBuf.toString().getBytes());

                            DataInputStream in = new DataInputStream(new FileInputStream(file));
                            int bytes = 0;
                            byte[] bufferOut = new byte[1024];
                            while ((bytes = in.read(bufferOut)) != -1) {
                                outStream.write(bufferOut, 0, bytes);
                            }
                            in.close();
                        }
                    }
                    if (!StringUtils.isEmpty(BOUNDARY)) {
                        byte[] endData = ("\r\n--" + BOUNDARY + "--\r\n").getBytes();
                        outStream.write(endData);
                    }
                    outStream.flush();
                    outStream.close();
                } else {
                    conn.setRequestProperty("Content-Length", "" + contentLength);
                }
            }

            if (requestMethod.equals("GET")) {
                //连接服务器
                conn.connect();
            }

            /// TODO: 2016/11/29 返回状态码需要后期完善，还需要对返回流，考虑字节流和图片流的区分，具体再问马工
            System.out.println(conn.getResponseCode());//响应码
            resultStr = readStrByCode(conn.getInputStream(), "utf-8");
            System.out.println(requestMethod + "请求[" + baseUrl + apiUrl + "]成功，请求结果：" + resultStr);
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println(requestMethod + "请求[" + baseUrl + apiUrl + "]Exception：" + e.getMessage());
        }

        if (filePath != null && filePath != "") {
            try {
                File fileDel = new File(filePath);
                fileDel.delete();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return resultStr;
    }

    /**
     * 以指定的格式来读取输入流
     */
    private static String readStrByCode(InputStream is, String code) {
        StringBuilder builder = new StringBuilder();
        BufferedReader reader = null;

        try {
            reader = new BufferedReader(new InputStreamReader(is, code));
            String line;
            while ((line = reader.readLine()) != null) {
                builder.append(line + "\n");
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                reader.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        return builder.toString();
    }

    /**
     * 加载请求的path参数
     *
     * @param params
     * @return
     */
    private static StringBuffer loadParamStr(Map<String, Object> params) {
        StringBuffer paramtersb = new StringBuffer("");
        try {
            if (params != null) {
                Iterator it = params.keySet().iterator();
                paramtersb = new StringBuffer("?");
                while (it.hasNext()) {
                    String key = (String) it.next();
                    Object val = params.get(key);
                    if (val instanceof String[]) {
                        String[] s = (String[]) val;
                        paramtersb.append(key).append("=").append(URLEncoder.encode(s[0], "utf-8")).append("&");
                    } else {
                        paramtersb.append(key).append("=").append(URLEncoder.encode(val.toString(), "utf-8")).append("&");
                    }
                }
                paramtersb.deleteCharAt(paramtersb.length() - 1);
            }
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return paramtersb;
    }

    /**
     * 发送POST请求
     *
     * @param url 目的地址            请求参数，Map类型。
     * @param map the map
     * @return 远程响应结果 string
     */
    public static String sendPost(String url, Map<String, Object> map) {
        String result = "";// 返回的结果
        BufferedReader in = null;// 读取响应输入流
        PrintWriter out = null;
        StringBuffer sb = new StringBuffer();// 处理请求参数
        String params = "";
        try {
            Set es = map.entrySet();//所有参与传参的参数按照accsii排序（升序）
            Iterator it = es.iterator();
            while (it.hasNext()) {
                Map.Entry entry = (Map.Entry) it.next();
                String k = (String) entry.getKey();
                Object v = entry.getValue();
                if (null != v && !"".equals(v) && !"sign".equals(k) && !"key".equals(k)) {
                    sb.append(k + "=" + v + "&");
                }
            }
            String temp_params = sb.toString();
            if (temp_params.length() > 0) {
                params = temp_params.substring(0, temp_params.length() - 1);
            }
            // 创建URL对象
            URL connURL = new URL(url);
            // 打开URL连接
            HttpURLConnection httpConn = (HttpURLConnection) connURL
                    .openConnection();
            // 设置通用属性
            httpConn.setRequestProperty("Accept", "*/*");
            httpConn.setRequestProperty("Connection", "Keep-Alive");
            httpConn.setRequestProperty("User-Agent",
                    "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1)");
            // 设置POST方式
            httpConn.setDoInput(true);
            httpConn.setDoOutput(true);
            // 获取HttpURLConnection对象对应的输出流
            out = new PrintWriter(httpConn.getOutputStream());
            // 发送请求参数
            //out.write(params);
            out.write(params);
            // flush输出流的缓冲
            out.flush();
            // 定义BufferedReader输入流来读取URL的响应，设置编码方式
            in = new BufferedReader(new InputStreamReader(httpConn
                    .getInputStream(), "utf-8"));
            String line;
            // 读取返回的内容
            while ((line = in.readLine()) != null) {
                result += line;

            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (out != null) {
                    out.close();
                }
                if (in != null) {
                    in.close();
                }
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
        return result;
    }

    /**
     * 处理请求
     * @param baseUrl
     * @param apiUrl
     * @param paramMap
     * @param headers
     * @return
     */
    public static String send_UnirestItembank_post(String baseUrl, String apiUrl, Map<String ,Object> paramMap, Map<String, String> headers) {
        try {
            Unirest.setTimeouts(10000L,60000L);
            if(headers == null){
                headers = new HashMap<>();
                headers.put("Authorization","Basic YTE5NjNhYzA4MTY1NWE2YToyMzFhNzFjMWZlYmI0MTFkOGFmZjAwNDgxOWZjMTgzZA==");
            }else if(!headers.containsKey("Authorization")){
                headers.put("Authorization","Basic YTE5NjNhYzA4MTY1NWE2YToyMzFhNzFjMWZlYmI0MTFkOGFmZjAwNDgxOWZjMTgzZA==");
            }
            HttpResponse<String> response = Unirest.post(baseUrl+apiUrl)
                    .headers(headers)
                    .header("Content-Type", "application/json")
                    .body(JSONObject.valueToString(paramMap))
                    .asString();

            logger.info("POST请求["+baseUrl+apiUrl+"]，body："+ JSONObject.valueToString(paramMap));
            if(response.getStatus()== HttpStatus.OK.value()){
                logger.info("POST请求["+baseUrl+apiUrl+"]成功，请求结果："+response.getBody());
                return response.getBody();
            }
        } catch (UnirestException e) {
            logger.error("请求异常：",e);
        }
        return null;
    }


    public static String send_UnirestRecoredSaving_post(String baseUrl, String apiUrl, Map<String ,Object> paramMap, Map<String, String> headers) {
        if(!StringUtils.isEmpty(baseUrl)){
            try {
                Unirest.setTimeouts(10000L,60000L);
                HttpResponse<String> response = Unirest.post(baseUrl+apiUrl)
                        .headers(headers)
                        .header("Content-Type", "application/json")
                        .body(new GsonBuilder().disableHtmlEscaping().create().toJson(paramMap))
                        .asString();

                logger.info("POST请求["+baseUrl+apiUrl+"]，body："+ JSONObject.valueToString(paramMap));
                if(response.getStatus()== HttpStatus.OK.value()){
                    logger.info("POST请求["+baseUrl+apiUrl+"]成功，请求结果："+response.getBody());
                    return response.getBody();
                }
            } catch (UnirestException e) {
                logger.error("请求异常：",e);
            }
        }
        return null;
    }

    public static String sendGet(String url,Map<String,String> headers) {
        HttpResponse<String> response = null;
        try {
            response = Unirest.get(url)
                    .headers(headers)
                    .header("User-Agent", USER_AGENT)
                    .asString();

        } catch (UnirestException e) {
            e.printStackTrace();
        }
        if(response != null && response.getStatus() == HttpStatus.OK.value()){
            return response.getBody();
        }else{
            return null;
        }
    }

    public static String sendPut(String url,Map<String,String> headers){
        HttpResponse<String> response = null;
        try {
            response = Unirest.put(url)
                    .headers(headers)
                    .header("User-Agent", USER_AGENT)
                    .asString();


        } catch (UnirestException e) {
            e.printStackTrace();
        }
        if(response != null && response.getStatus() == HttpStatus.OK.value()){
            return response.getBody();
        }else{
            return null;
        }
    }

    /**
     * post 请求(传参为form-data格式)
     * @param url
     * @param param 例：student_code=T0802202103941803000033&secret=DBF226E4E9904DCB48C86D0076E25708
     * @return
     */
    public static String sendPostFromData(String url, Map<String,Object> param) {
        PrintWriter out = null;
        BufferedReader in = null;
        String result = "";
        StringBuilder strParam = new StringBuilder("");
        try {
            URL realUrl = new URL(url);
            // 打开和URL之间的连接
            URLConnection conn = realUrl.openConnection();
            // 设置通用的请求属性
            conn.setRequestProperty("accept", "*/*");
            conn.setRequestProperty("connection", "Keep-Alive");
            conn.setRequestProperty("user-agent",
                    "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
            // 发送POST请求必须设置如下两行
            conn.setDoOutput(true);
            conn.setDoInput(true);
            // 获取URLConnection对象对应的输出流
            out = new PrintWriter(conn.getOutputStream());
            // 发送请求参数
            Iterator<Map.Entry<String, Object>> iterator = param.entrySet().iterator();
            int count = 0;
            while (iterator.hasNext()){
                Map.Entry<String, Object> next = iterator.next();
                if(count == (param.size() - 1)){
                    strParam.append(next.getKey()).append("=").append(next.getValue());
                }else{
                    strParam.append(next.getKey()).append("=").append(next.getValue()).append("&");
                    count++;
                }
            }
            out.print(strParam.toString());
            // flush输出流的缓冲
            out.flush();
            // 定义BufferedReader输入流来读取URL的响应
            in = new BufferedReader(
                    new InputStreamReader(conn.getInputStream(),"utf-8"));
            String line;
            while ((line = in.readLine()) != null) {
                result += line;
            }
        } catch (Exception e) {
            System.out.println("发送 POST 请求出现异常！"+e);
            e.printStackTrace();
        }
        //使用finally块来关闭输出流、输入流
        finally{
            try{
                if(out!=null){
                    out.close();
                }
                if(in!=null){
                    in.close();
                }
            }
            catch(IOException ex){
                ex.printStackTrace();
            }
        }
        return result;
    }

}